/*
 * Copyright Hundsun Technologies Inc. All Rights Reserved.
 */

package genesisblock

import (
	"errors"

	"github.com/golang/protobuf/proto"
	"hundsun.com/hsl/hschain/protos/config"
	"hundsun.com/hsl/hschain/protos/ledger"
)

//#####################Solo共识相关#####################

// SoloGenesisBlockYamlConfig  采用Solo共识的创世块yaml文件对应的结构体
type SoloGenesisBlockYamlConfig struct {
	BaseGenesisBlockYamlConfig `yaml:",inline"`
	Consensus                  *SoloConsensusConfig
}

// ConvertToProtoMessage 在基类的基础上，解析了共识字段
func (s *SoloGenesisBlockYamlConfig) ConvertToProtoMessage() error {
	err := s.BaseGenesisBlockYamlConfig.ConvertToProtoMessage()
	if err != nil {
		return err
	}

	consensusConfigBytes, err := s.Consensus.Payload.ConvertToProtoMessageBytes()
	if err != nil {
		return err
	}

	s.genesisTxPayload.Consensus = &config.ConsensusConfig{
		Type:    config.SoloConsensusType,
		Payload: consensusConfigBytes,
	}

	err = s.genesisTxPayload.Validate()
	if err != nil {
		return err
	}
	return nil
}

// InitFromProtoMessage 在基类的基础上解析了consensus字段
func (s *SoloGenesisBlockYamlConfig) InitFromProtoMessage(genesisBlock *ledger.Block) error {
	err := s.BaseGenesisBlockYamlConfig.InitFromProtoMessage(genesisBlock)
	if err != nil {
		return err
	}
	s.Consensus = &SoloConsensusConfig{}
	s.Consensus.Type = config.SoloConsensusType
	s.Consensus.Payload = &SoloConsensusConfigPayload{}
	return s.Consensus.Payload.InitFromProtoMessageBytes(s.genesisTxPayload.Consensus.Payload)
}

// SoloConsensusConfig Solo共识对应的consensus配置对象
type SoloConsensusConfig struct {
	BaseConsensusConfig `yaml:",inline"`
	Payload             *SoloConsensusConfigPayload `yaml:"payload"`
}

// SoloConsensusConfigPayload solo共识相关配置
type SoloConsensusConfigPayload struct {
	Address string `yaml:"minerAddress"`
	PeerID  string `yaml:"peerID"`
}

//ConvertToProtoMessageBytes ...
func (s *SoloConsensusConfigPayload) ConvertToProtoMessageBytes() ([]byte, error) {
	if len(s.Address) == 0 {
		return nil, errors.New("consensus.payload.minerAddress not found or is empty")
	}
	pbPayload := &config.SoloConsensusConfigPayload{
		Address: s.Address,
		PeerID:  s.PeerID,
	}
	err := pbPayload.Validate()
	if err != nil {
		return nil, err
	}
	pbPayloadBytes, err := proto.Marshal(pbPayload)
	if err != nil {
		return nil, err
	}
	return pbPayloadBytes, nil
}

//InitFromProtoMessageBytes ...
func (s *SoloConsensusConfigPayload) InitFromProtoMessageBytes(bytes []byte) error {
	pbConsensusConfigPayload := config.SoloConsensusConfigPayload{}
	err := proto.Unmarshal(bytes, &pbConsensusConfigPayload)
	if err != nil {
		return err
	}
	s.Address = pbConsensusConfigPayload.Address
	s.PeerID = pbConsensusConfigPayload.PeerID
	return nil
}
